#ifndef __I2C_CONFIG_H
#define __I2C_CONFIG_H

#include "stm32f10x.h"
#include "stdbool.h"
#include "stdio.h"

/**
  ******************************************************************************
  * @file    I2C_Config.h
  * @brief   STM32硬件I2C总线驱动头文件
  * @author  18408107475@163.com
  * @version V1.0
  * @date    2025-7-15
  * @note    功能说明：
  *          - 基于STM32硬件I2C外设实现通信驱动
  *          - 支持标准I2C协议（7位地址，100kHz速率）
  *          - 提供单字节/多字节读写接口，兼容大多数I2C设备
  * @硬件依赖：
  *          - 需外接4.7KΩ上拉电阻到VCC
  *          - 支持的设备地址：7位地址（自动转换为8位含读写标志）
  ******************************************************************************
  */

/**
  * @brief  I2C硬件配置宏定义
  * @note   需根据实际硬件连接修改以下参数：
  *         - I2C_PORT：I2C1对应的GPIO端口
  *         - I2C_SCL_PIN：SCL时钟线引脚
  *         - I2C_SDA_PIN：SDA数据线引脚
  *         - I2C_GPIO_CLK：GPIO端口时钟
  *         - I2C_CLK：I2C1外设时钟
  */
#define I2C_CLK         RCC_APB1Periph_I2C2
#define I2C_GPIO_CLK    RCC_APB2Periph_GPIOB
#define I2C_PORT        GPIOB       // SCL时钟线GPIO端口
#define I2C_SCL_PIN     GPIO_Pin_10  // SCL引脚号
#define I2C_SDA_PIN     GPIO_Pin_11  // SDA引脚号

#define I2C_TIMEOUT_MAX 10000  // 可根据实际情况调整

/**
  * @brief  等待I2C特定事件发生（私有辅助函数声明）
  * @param  I2Cx: 目标I2C外设（如I2C1）
  * @param  event: 待等待的事件（如I2C_EVENT_MASTER_MODE_SELECT）
  * @retval true: 事件发生，false: 超时（事件未发生）
  * @note   内部使用的状态检测函数，用于轮询I2C状态寄存器
  *         超时机制防止总线异常时程序卡死
  */
static bool I2C_WaitEvent(I2C_TypeDef* I2Cx, uint32_t event);

/**
  * @brief  初始化I2C1外设及对应GPIO
  * @note   配置流程：
  *         1. 使能GPIO和I2C时钟
  *         2. 配置GPIO为复用开漏模式（I2C总线必需）
  *         3. 配置I2C1参数（速率、地址模式、应答等）
  *         4. 使能I2C1外设
  * @硬件配置细节：
  *         - GPIO模式：AF_OD（复用开漏）→ 支持I2C总线的线与逻辑
  *         - 时钟速度：100000Hz（标准模式，兼容大多数设备）
  *         - 地址模式：7位地址（主流I2C设备采用）
  *         - 应答使能：I2C_Ack_Enable → 接收数据时发送ACK
  */
void I2C_Config(void);

/**
  * @brief  向I2C设备的指定寄存器写入单字节数据
  * @param  dev_addr: 设备7位I2C地址（如0x68）
  * @param  reg_addr: 目标寄存器地址（如MPU6050的PWR_MGMT_1）
  * @param  data: 要写入的数据字节
  * @retval true: 写入成功, false: 写入失败（含超时）
  * @I2C通信时序：
  *         START → 设备地址（写） → ACK → 寄存器地址 → ACK → 数据 → ACK → STOP
  */
bool I2C_Write_Data(u8 dev_addr, u8 reg_addr, u8 data);

/**
  * @brief  从I2C设备的指定寄存器读取单字节数据
  * @param  dev_addr: 设备7位I2C地址（如0x3C）
  * @param  reg_addr: 目标寄存器地址（如OLED的0x00命令寄存器）
  * @retval 读取到的数据（失败时返回0）
  * @I2C通信时序：
  *         START → 设备地址（写） → ACK → 寄存器地址 → ACK → 
  *         RESTART → 设备地址（读） → ACK → 数据 → NACK → STOP
  * @注意事项：
  *         1. 返回0可能表示通信失败，需结合设备寄存器默认值判断
  *         2. 单字节读取时最后需发送NACK告知从机停止发送
  */
u8 I2C_Read_Data(u8 dev_addr, u8 reg_addr);

/**
  * @brief  向I2C设备的指定寄存器写入多字节数据
  * @param  dev_addr: 设备7位I2C地址
  * @param  reg_addr: 目标寄存器地址
  * @param  len: 数据长度（字节数）
  * @param  data: 要写入的数据数组指针（需保证非NULL）
  * @retval true: 写入成功, false: 写入失败
  * @I2C通信时序：
  *         START → 设备地址（写） → ACK → 寄存器地址 → ACK → 
  *         数据1 → ACK → 数据2 → ACK → ... → 数据n → ACK → STOP
  * @性能提示：
  *         连续写入多个字节时，多数I2C设备会自动递增寄存器地址
  */
bool I2C_Write_MultiData(u8 dev_addr, u8 reg_addr, u8 len, u8* data);

/**
  * @brief  从I2C设备的指定寄存器读取多字节数据
  * @param  dev_addr: 设备7位I2C地址
  * @param  reg_addr: 目标寄存器地址
  * @param  len: 要读取的数据长度（字节数）
  * @param  data: 存储读取数据的数组指针（需保证非NULL且足够大）
  * @retval true: 读取成功, false: 读取失败
  * @I2C通信时序：
  *         START → 设备地址（写） → ACK → 寄存器地址 → ACK → 
  *         RESTART → 设备地址（读） → ACK → 数据1 → ACK → ... → 数据n → NACK → STOP
  * @应答控制：
  *         - 前n-1个字节：主机接收后发送ACK（继续传输）
  *         - 最后1个字节：主机接收前发送NACK（终止传输）
  */
bool I2C_Read_MultiData(u8 dev_addr, u8 reg_addr, u8 len, u8* data);

#endif